// concept.hpp
#include <memory>

#ifdef __GNUC__
#define TEMPLATE_SPEC_DECL      , typename TEMPLATE_SPEC_T = int
#define TEMPLATE_SPEC_PART      typename TEMPLATE_SPEC_T
#define TEMPLATE_SPEC           , TEMPLATE_SPEC_T
#define TEMPLATE_SPEC_DECL1     , typename TEMPLATE_SPEC_T1 = int
#define TEMPLATE_SPEC_PART1     typename TEMPLATE_SPEC_T1
#define TEMPLATE_SPEC1          , TEMPLATE_SPEC_T1
#else
#define TEMPLATE_SPEC_DECL
#define TEMPLATE_SPEC_PART
#define TEMPLATE_SPEC
#define TEMPLATE_SPEC_DECL1
#define TEMPLATE_SPEC_PART1
#define TEMPLATE_SPEC1
#endif

#ifdef _MSC_VER
#define MEMFUNCCAST(A)          reinterpret_cast<A>
#else
#define MEMFUNCCAST(A)
#endif

#if !defined(_MSC_VER) || _MSC_VER >= 1300
#define CONCEPT_IF_NOT_VC6_3(A, B, C)   A, B, C
#define CONCEPT_IF_VC6_ELSE(A, B)       B
#define CONCEPT_ALLOCATOR_REBIND(CONCEPTNAME)
#define CONCEPT_BIND(CONCEPTNAME)
#else
#define CONCEPT_IF_NOT_VC6_3(A, B, C)
#define CONCEPT_IF_VC6_ELSE(A, B)       A
#define CONCEPT_ALLOCATOR_REBIND(ALLOCATORNAME) \
namespace Concept \
{ \
template <> \
struct concept_rebind_allocator<ALLOCATORNAME > \
{ \
    template <class T> \
    struct with \
    { \
        typedef ALLOCATORNAME::rebind<T>::other other; \
    }; \
}; \
}
#define CONCEPT_BIND(CONCEPTNAME) \
namespace Concept \
{ \
template <> \
struct concept_bind<CONCEPTNAME > \
{ \
    typedef CONCEPTNAME ConceptName; \
    template <class BaseType, class BaseFrom, bool isvtable, class ObjectType> \
    struct with : public CONCEPTNAME::template table<BaseFrom, isvtable, ObjectType> \
    { \
        typedef BaseType Base; \
        typedef BaseFrom DeriveFrom; \
    }; \
}; \
} // namespace Concept
#endif

#define CONCEPT_MAP(CONCEPTNAME, TYPE) \
namespace Concept \
{ \
template <> struct concept_map<CONCEPTNAME, TYPE> {}; \
}

#define CONCEPT_FUNCTION(CONCEPTNAME, FNAME, RTYPE, FTYPE, PARA) \
struct CONCEPTNAME \
{ \
    typedef CONCEPTNAME ConceptName; \
    template <bool isvtable TEMPLATE_SPEC_DECL> \
    struct ifvtable \
    { \
        template <class ReturnType> \
        struct rt \
        { \
            template <class ObjectType, class BaseFrom> \
            struct table : public Concept::concept_bind_with<typename BaseFrom::Base, typename BaseFrom::DeriveFrom, isvtable, ObjectType>::type \
            { \
                typedef typename Concept::get_type<RTYPE (*)FTYPE>::type function_type; \
                function_type p##FNAME; \
                table() : p##FNAME(&::FNAME) {} \
            }; \
        }; \
    }; \
    template <TEMPLATE_SPEC_PART> \
    struct ifvtable<false TEMPLATE_SPEC> \
    { \
        template <class ReturnType TEMPLATE_SPEC_DECL1> \
        struct rt \
        { \
            template <class ObjectType, class BaseFrom> \
            struct table : public Concept::concept_bind_with<typename BaseFrom::Base, typename BaseFrom::DeriveFrom, false, ObjectType>::type \
            { \
                const void* CONCEPTNAME##_index() const {return this;} \
                static RTYPE FNAME FTYPE \
                { \
                    return (*t.ptable->p##FNAME)PARA; \
                } \
            }; \
        }; \
        template <TEMPLATE_SPEC_PART1> \
        struct rt<void TEMPLATE_SPEC1> \
        { \
            template <class ObjectType, class BaseFrom> \
            struct table : public Concept::concept_bind_with<typename BaseFrom::Base, typename BaseFrom::DeriveFrom, false, ObjectType>::type \
            { \
                const void* CONCEPTNAME##_index() const {return this;} \
                static RTYPE FNAME FTYPE \
                { \
                    (*t.ptable->p##FNAME)PARA; \
                } \
            }; \
        }; \
    }; \
    template <class BaseFrom = concept_base, bool isvtable = true, class ObjectType = concept_object> \
    struct table : public ifvtable<isvtable>::template rt<RTYPE>::template table<ObjectType, BaseFrom> \
    { \
        typedef CONCEPTNAME Base; \
        typedef BaseFrom DeriveFrom; \
    }; \
}; \
CONCEPT_BIND(CONCEPTNAME);

#define CONCEPT_MEMBER_FUNCTION(CONCEPTNAME, FNAME, RTYPE, FTYPE, PARA) \
struct CONCEPTNAME \
{ \
    typedef CONCEPTNAME ConceptName; \
    template <bool isvtable TEMPLATE_SPEC_DECL> \
    struct ifvtable \
    { \
        template <class ReturnType> \
        struct rt \
        { \
            template <class ObjectType, class BaseFrom> \
            struct table : public Concept::concept_bind_with<typename BaseFrom::Base, typename BaseFrom::DeriveFrom, isvtable, ObjectType>::type \
            { \
                typedef typename Concept::get_type<RTYPE (ObjectType::*)FTYPE>::type function_type; \
                function_type p##FNAME; \
                table() : p##FNAME(MEMFUNCCAST(function_type)(&ObjectType::FNAME)) {} \
            }; \
        }; \
    }; \
    template <TEMPLATE_SPEC_PART> \
    struct ifvtable<false TEMPLATE_SPEC> \
    { \
        template <class ReturnType TEMPLATE_SPEC_DECL1> \
        struct rt \
        { \
            template <class ObjectType, class BaseFrom> \
            struct table : public Concept::concept_bind_with<typename BaseFrom::Base, typename BaseFrom::DeriveFrom, false, ObjectType>::type \
            { \
                const void* CONCEPTNAME##_index() const {return this;} \
                RTYPE FNAME FTYPE \
                { \
                    typedef typename ObjectType::TableType TableType; \
                    typedef typename TableType::conceptType conceptType; \
                    typedef concept<conceptType> concept_Type; \
                    ObjectType* This = reinterpret_cast<ObjectType*>( \
                        reinterpret_cast<size_t>(this) - \
                        reinterpret_cast<size_t>( \
                            reinterpret_cast<concept_Type*>(0)->CONCEPTNAME##_index())); \
                    return (This->object_pointer->*This->ptable->p##FNAME)PARA; \
                } \
            }; \
        }; \
        template <TEMPLATE_SPEC_PART1> \
        struct rt<void TEMPLATE_SPEC1> \
        { \
            template <class ObjectType, class BaseFrom> \
            struct table : public Concept::concept_bind_with<typename BaseFrom::Base, typename BaseFrom::DeriveFrom, false, ObjectType>::type \
            { \
                const void* CONCEPTNAME##_index() const {return this;} \
                RTYPE FNAME FTYPE \
                { \
                    typedef typename ObjectType::TableType TableType; \
                    typedef typename TableType::conceptType conceptType; \
                    typedef concept<conceptType> concept_Type; \
                    ObjectType* This = reinterpret_cast<ObjectType*>( \
                        reinterpret_cast<size_t>(this) - \
                        reinterpret_cast<size_t>( \
                            reinterpret_cast<concept_Type*>(0)->CONCEPTNAME##_index())); \
                    (This->object_pointer->*This->ptable->p##FNAME)PARA; \
                } \
            }; \
        }; \
    }; \
    template <class BaseFrom = concept_base, bool isvtable = true, class ObjectType = concept_object> \
    struct table : public ifvtable<isvtable>::template rt<RTYPE>::template table<ObjectType, BaseFrom> \
    { \
        typedef CONCEPTNAME Base; \
        typedef BaseFrom DeriveFrom; \
    }; \
}; \
CONCEPT_BIND(CONCEPTNAME);

namespace Concept
{

template <class T> struct get_type {typedef T type;};

struct concept_base;
struct concept_object{};
template <class conceptT = int, class T = int> struct concept_map {int t[2];};

template <class conceptT>
struct concept_bind
{
    typedef conceptT ConceptName;
    template <class BaseType, class BaseFrom, bool isvtable, class ObjectType>
    struct with CONCEPT_IF_NOT_VC6_3(: public conceptT::template table<BaseFrom, isvtable, ObjectType>)
    {
        typedef conceptT Base;
        typedef BaseFrom DeriveFrom;
    };
};

template <class conceptT, class BaseFrom = concept_base, bool isvtable = true, class ObjectType = concept_object>
struct concept_bind_with
{
    typedef typename concept_bind<typename conceptT::ConceptName>::template with<conceptT, BaseFrom, isvtable, ObjectType> type;
};

template <class Alloc>
struct concept_rebind_allocator
{
    template <class T>
    struct with
    {
        typedef std::allocator<T> other;
    };
};

template <class Alloc, class T>
struct concept_rebind_allocator_with
{
    typedef typename CONCEPT_IF_VC6_ELSE(
        concept_rebind_allocator<Alloc>::template with<T>::other, 
        Alloc::template rebind<T>::other) other;
};

struct concept_base
{
    typedef concept_base ConceptName;
    typedef concept_base Base;
    typedef concept_base DeriveFrom;
    template <class BaseFrom TEMPLATE_SPEC_DECL>
    struct from
    {
        template <bool isvtable, class ObjectType>
        struct table : public concept_bind_with<typename BaseFrom::Base, typename BaseFrom::DeriveFrom, isvtable, ObjectType>::type {};
    };
    template <TEMPLATE_SPEC_PART>
    struct from<concept_base TEMPLATE_SPEC>
    {
        template <bool isvtable, class ObjectType>
        struct table {};
    };
    template <class BaseFrom = concept_base, bool isvtable = true, class ObjectType = concept_object>
    struct table : public from<BaseFrom>::template table<isvtable, ObjectType>
    {
        typedef concept_base Base;
        typedef BaseFrom DeriveFrom;
    };
};

template <class C0 = concept_base,  class C1 = concept_base,  class C2 = concept_base,  class C3 = concept_base,  class C4 = concept_base,  
          class C5 = concept_base,  class C6 = concept_base,  class C7 = concept_base,  class C8 = concept_base,  class C9 = concept_base,  
          class C10 = concept_base, class C11 = concept_base, class C12 = concept_base, class C13 = concept_base, class C14 = concept_base, 
          class C15 = concept_base, class C16 = concept_base, class C17 = concept_base, class C18 = concept_base, class C19 = concept_base >
struct concept_list
{
    typedef concept_list<> ConceptName;
    typedef  C0  P0; typedef  C1  P1; typedef  C2  P2; typedef  C3  P3; typedef  C4  P4; typedef  C5  P5; typedef  C6  P6; typedef  C7  P7; typedef  C8  P8; typedef  C9  P9;
    typedef C10 P10; typedef C11 P11; typedef C12 P12; typedef C13 P13; typedef C14 P14; typedef C15 P15; typedef C16 P16; typedef C17 P17; typedef C18 P18; typedef C19 P19;
    typedef concept_list<P0,P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12,P13,P14,P15,P16,P17,P18,P19> concept_list_type;
    template <class BaseFrom = concept_base, bool isvtable = true, class T = concept_object>
    struct table : public
                 concept_bind_with< C0,typename concept_bind_with< C1,typename concept_bind_with< C2,typename concept_bind_with< C3,typename concept_bind_with< C4,
        typename concept_bind_with< C5,typename concept_bind_with< C6,typename concept_bind_with< C7,typename concept_bind_with< C8,typename concept_bind_with< C9,
        typename concept_bind_with<C10,typename concept_bind_with<C11,typename concept_bind_with<C12,typename concept_bind_with<C13,typename concept_bind_with<C14,
        typename concept_bind_with<C15,typename concept_bind_with<C16,typename concept_bind_with<C17,typename concept_bind_with<C18,typename concept_bind_with<C19,
        BaseFrom
        >::type>::type>::type>::type>::type>::type>::type>::type>::type>::type
        >::type>::type>::type>::type>::type>::type>::type>::type>::type, isvtable, T>::type
    {
        typedef concept_list Base;
        typedef BaseFrom DeriveFrom;
    };
};

template <>
struct concept_bind<concept_list<> >
{
    typedef concept_list<> ConceptName;
    template <class BaseType, class BaseFrom, bool isvtable, class ObjectType>
    struct with_type
    {
        typedef  typename BaseType::P0  P0; typedef  typename BaseType::P1  P1; typedef  typename BaseType::P2  P2; typedef  typename BaseType::P3  P3; typedef  typename BaseType::P4  P4;
        typedef  typename BaseType::P5  P5; typedef  typename BaseType::P6  P6; typedef  typename BaseType::P7  P7; typedef  typename BaseType::P8  P8; typedef  typename BaseType::P9  P9;
        typedef typename BaseType::P10 P10; typedef typename BaseType::P11 P11; typedef typename BaseType::P12 P12; typedef typename BaseType::P13 P13; typedef typename BaseType::P14 P14;
        typedef typename BaseType::P15 P15; typedef typename BaseType::P16 P16; typedef typename BaseType::P17 P17; typedef typename BaseType::P18 P18; typedef typename BaseType::P19 P19;
        typedef concept_list<P0,P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12,P13,P14,P15,P16,P17,P18,P19> concept_list_type;
        typedef typename concept_list_type::template table<BaseFrom, isvtable, ObjectType> type;
    };
    template <class BaseType, class BaseFrom, bool isvtable, class ObjectType>
    struct with : public with_type<BaseType, BaseFrom, isvtable, ObjectType>::type
    {
        typedef BaseType Base;
        typedef BaseFrom DeriveFrom;
    };
};

template <class TableT>
struct concept_class_base
{
    typedef TableT TableType;

    concept_object *object_pointer;
    TableT *ptable;

    operator const concept_object&() const { return *object_pointer; }
    operator concept_object&() { return *object_pointer; }
};

template <class conceptT, class Alloc = std::allocator<void>, class T = concept_object>
struct concept_table : public concept_bind_with<conceptT, concept_base, true, T>::type
{
    typedef conceptT conceptType;
    typedef typename concept_rebind_allocator_with<Alloc, T>::other allocatorT;

    template <class _Alloc>
    struct allocator_function_type
    {
        typedef typename _Alloc::pointer pointer;
        typedef typename _Alloc::size_type size_type;
        typedef pointer (_Alloc::*type_allocate)(size_type n, const void *hint);
        typedef void (_Alloc::*type_deallocate)(pointer p, size_type n);
        typedef void (_Alloc::*type_construct)(pointer p, const T& val);
        typedef void (_Alloc::*type_destroy)(pointer p);
    };
    typedef typename allocator_function_type<allocatorT>::type_allocate type_allocate;
    typedef typename allocator_function_type<allocatorT>::type_deallocate type_deallocate;
    typedef typename allocator_function_type<allocatorT>::type_construct type_construct;
    typedef typename allocator_function_type<allocatorT>::type_destroy type_destroy;

    type_allocate allocate;
    type_deallocate deallocate;
    type_construct construct;
    type_destroy destroy;
    allocatorT *allocator;

    concept_table() : 
        allocator(new allocatorT), 
        allocate(&allocatorT::allocate), 
        deallocate(reinterpret_cast<type_deallocate>(&allocatorT::deallocate)), 
        construct(&allocatorT::construct), 
        destroy(&allocatorT::destroy) {}

    static concept_table* vtable()
    {
        static concept_table static_table;
        return &static_table;
    }
};

template <class conceptT, class Alloc = std::allocator<void> >
class auto_concept;
template <class conceptT, class Alloc = std::allocator<void> >
class ref_concept;
template <class conceptT, class Alloc = std::allocator<void> >
class ref_auto_concept;

template <class conceptT, bool isauto = false, bool isref = false, class Alloc = std::allocator<void> >
class concept : 
    public concept_class_base<concept_table<conceptT, Alloc> >, 
    public concept_bind_with<conceptT, concept_base, false, concept_class_base<concept_table<conceptT, Alloc> > >::type
{
public:
    using concept_class_base<concept_table<conceptT, Alloc> >::ptable;
    using concept_class_base<concept_table<conceptT, Alloc> >::object_pointer;
    typedef concept_table<conceptT, Alloc> TableType;
private:
	void init_with(concept_object* p, TableType* pTable)
    {
        ptable = pTable;
        if (isref)
        {
            object_pointer = p;
        }
        else
        {
            object_pointer = (ptable->allocator->*ptable->allocate)(1, p);
            (ptable->allocator->*ptable->construct)(object_pointer, *p);
        }
    }
public:
    template <class T>
    concept(const T& t)
    {
        if (0) char static_assert[isauto || sizeof(concept_map<>) != sizeof(concept_map<conceptT, T>) ? 1 : -1];
        typedef concept_table<conceptT, Alloc, T> cTable;
        init_with(const_cast<concept_object *>(reinterpret_cast<const concept_object *>(&t)), 
        	      (reinterpret_cast<TableType*>(cTable::vtable())));
    }

    concept(const concept& rhs) { init_with(rhs.object_pointer, rhs.ptable); }
    concept(const concept<conceptT, isauto, !isref, Alloc>& rhs) { init_with(rhs.object_pointer, rhs.ptable); }
    concept(const concept<conceptT, !isauto, isref, Alloc>& rhs) { init_with(rhs.object_pointer, rhs.ptable); }
    concept(const concept<conceptT, !isauto, !isref, Alloc>& rhs) { init_with(rhs.object_pointer, rhs.ptable); }
    concept(const auto_concept<conceptT, Alloc>& rhs) { init_with(rhs.object_pointer, rhs.ptable); }
    concept(const ref_concept<conceptT, Alloc>& rhs) { init_with(rhs.object_pointer, rhs.ptable); }
    concept(const ref_auto_concept<conceptT, Alloc>& rhs) { init_with(rhs.object_pointer, rhs.ptable); }

    ~concept()
    {
        if (!isref)
        {
            (ptable->allocator->*ptable->destroy)(object_pointer);
            (ptable->allocator->*ptable->deallocate)(object_pointer, 1);
        }
    }

    concept& operator = (const concept& rhs)
    {
        concept(rhs).swap(*this);
        return *this;
    }

    void swap(concept& rhs)
    {
        concept_object *pointer0 = object_pointer;
        TableType *ptable0 = ptable;
        object_pointer = rhs.object_pointer;
        ptable = rhs.ptable;
        rhs.object_pointer = pointer0;
        rhs.ptable = ptable0;
    }
};

template <class conceptT, class Alloc>
class auto_concept : public concept<conceptT, true, false, Alloc>
{
public:
    template <class T>
    auto_concept(const T& t) : concept<conceptT, true, false, Alloc>(t) {}
};

template <class conceptT, class Alloc>
class ref_concept : public concept<conceptT, false, true, Alloc>
{
public:
    template <class T>
    ref_concept(const T& t) : concept<conceptT, false, true, Alloc>(t) {}
};

template <class conceptT, class Alloc>
class ref_auto_concept : public concept<conceptT, true, true, Alloc>
{
public:
    template <class T>
    ref_auto_concept(const T& t) : concept<conceptT, true, true, Alloc>(t) {}
};

} // namespace Concept
